﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ThreadingApp1
{
    /// <summary>
    /// Klasa zawiera produkty wyprodukowane przez producenta. Można pobierać lub dodawać produkty. Ilość produktow jest ograniczona.
    /// Obsługa dodawania i usuwania musi być thread-safe. Wykorzystano do tego celu semafory.
    /// </summary>
    public class Storehouse
    {
        int numOfProducts;
        Stack<string> products;
        Semaphore makerSemaphore;
        Semaphore consumerSemaphore;

        public Storehouse(int numOfProducts)
        {
            this.numOfProducts = numOfProducts;
            products = new Stack<string>(numOfProducts);
            makerSemaphore = new Semaphore(1, 1, "MakerSemaphore");
            consumerSemaphore = new Semaphore(1, 1, "ConsumerSemaphore");
        }


        /// <summary>
        /// Dodaje produkt do lisy jeżeli jest na niego miejsce.
        /// Produkty będą dodawane przez producenta. Operacja dodawania jest thread-safe.
        /// </summary>
        /// <param name="name">Nazwa produktu</param>
        /// <returns><c>True</c> jeżli produkt został dodany do magazynu</returns>
        public bool AddProduct(string name)
        {

            if (products.Count < numOfProducts)
            {
                //Sekcja krytyczna
                makerSemaphore.WaitOne();
                products.Push(name);
                makerSemaphore.Release();
                return true;
            }

            return false;
        }

        /// <summary>
        /// Usuwa ostani produkt z list.
        /// Produkty będą usuwane przez konsumentów. Operacja thread-safe.
        /// </summary>
        public string ConsumeProduct()
        {

            if (products.Count > 0)
            {
                //sekcja krytyczna
                consumerSemaphore.WaitOne();
                string p = products.Pop();
                consumerSemaphore.Release();
                return p;
            }

            return null;
        }

    }
}
